import {
	IUIEngineInputParam,
	IUIEngineModel,
	IUIEngineResult,
} from '@/core/interface';
import { CtrlEventUIEngine } from './ctrl-event-engine';
import { CustomUIEngine } from './custom-engine';
import { ItemUIEngine } from './item-engine';
import { PanelEventUIEngine } from './panel-event-engine';
import { TimerUIEngine } from './timer-engine';
import { ViewEventUIEngine } from './view-event-engine';

/**
 * 界面引擎容器
 *
 * @export
 * @class UIEngineContainer
 * @template A
 */
export class UIEngineContainer<A> {
	/**
	 * 视图事件界面引擎Map
	 *
	 * @private
	 * @type {Map<string, ViewEventUIEngine<A>[]>}
	 * @memberof UIEngineContainer
	 */
	private viewEventUIEngineMap: Map<string, ViewEventUIEngine<A>[]> = new Map();

	/**
	 * 部件事件界面引擎Map
	 *
	 * @private
	 * @type {Map<string, CtrlEventUIEngine<A>[]>}
	 * @memberof UIEngineContainer
	 */
	private ctrlEventUIEngineMap: Map<string, CtrlEventUIEngine<A>[]> = new Map();

	/**
	 * 部件事件界面引擎Map
	 *
	 * @private
	 * @type {Map<string, PanelEventUIEngine<A>[]>}
	 * @memberof UIEngineContainer
	 */
	private panelEventUIEngineMap: Map<string, PanelEventUIEngine<A>[]> =
		new Map();

	/**
	 * 计数器界面引擎Map
	 *
	 * @private
	 * @type {Map<string, TimerUIEngine<A>>}
	 * @memberof UIEngineContainer
	 */
	private timerUIEngineMap: Map<string, TimerUIEngine<A>> = new Map();

	/**
	 * 自定义界面引擎Map
	 *
	 * @private
	 * @type {Map<string, CustomUIEngine<A>>}
	 * @memberof UIEngineContainer
	 */
	private customUIEngineMap: Map<string, CustomUIEngine<A>> = new Map();

	/**
	 * 项显示逻辑引擎
	 *
	 * @private
	 * @type {Map<string, CustomUIEngine<A>>}
	 * @memberof UIEngineContainer
	 */
	private itemUIEngineMap: Map<string, ItemUIEngine<A>> = new Map();

	/**
	 * 事件分隔符
	 *
	 * @private
	 * @type {string}
	 * @memberof UIEngineContainer
	 */
	private eventSeparator: string = ';';

	/**
	 * Creates an instance of UIEngineContainer.
	 * @param {IUIEngineModel[]} model
	 * @memberof UIEngineContainer
	 */
	public constructor(model: IUIEngineModel[]) {
		this.init(model);
	}

	/**
	 * 初始化界面引擎容器
	 *
	 * @private
	 * @param {IUIEngineModel[]} model
	 * @memberof UIEngineContainer
	 */
	private init(model: IUIEngineModel[]) {
		if (model && model.length > 0) {
			for (let item of model) {
				this.initUIEngine(item);
			}
		}
	}

	/**
	 * 初始化界面引擎执行器
	 *
	 * @private
	 * @param {IUIEngineModel} model
	 * @memberof UIEngineContainer
	 */
	private initUIEngine(model: IUIEngineModel) {
		if (!model) return;
		switch (model.triggerType) {
			case 'VIEWEVENT':
				this.initEventNameUIEngine(
					model.eventNames,
					this.viewEventUIEngineMap,
					new ViewEventUIEngine<A>(model),
					model.psViewCtrlName
				);
				break;
			case 'CTRLEVENT':
				this.initEventNameUIEngine(
					model.eventNames,
					this.ctrlEventUIEngineMap,
					new CtrlEventUIEngine<A>(model)
				);
				break;
			case 'PANELEVENT':
				this.initEventNameUIEngine(
					model.eventNames,
					this.panelEventUIEngineMap,
					new PanelEventUIEngine<A>(model),
					model.psViewCtrlName
				);
				break;
			case 'TIMER':
				this.timerUIEngineMap.set(model.name, new TimerUIEngine<A>(model));
				break;
			case 'ITEMVISIBLE':
			case 'ITEMENABLE':
			case 'ITEMBLANK':
				this.itemUIEngineMap.set(model.name, new ItemUIEngine<A>(model));
				break;
			case 'CUSTOM':
				this.customUIEngineMap.set(model.name, new CustomUIEngine<A>(model));
				break;
			default:
				console.log(`${model.name}暂不支持`);
				break;
		}
	}

	/**
	 * 初始化事件名称界面引擎
	 *
	 * @param {string} eventNames
	 * @param {(PanelEventUIEngine<A> | CtrlEventUIEngine<A> | ViewEventUIEngine<A>)} UIEngine
	 * @memberof UIEngineContainer
	 */
	public initEventNameUIEngine(
		eventNames: string,
		map: Map<string, any[]>,
		UIEngine:
			| PanelEventUIEngine<A>
			| CtrlEventUIEngine<A>
			| ViewEventUIEngine<A>,
		ctrlName?: string
	) {
		const eventArray = eventNames.split(this.eventSeparator);
		eventArray.forEach((item: string) => {
			const tag = ctrlName
				? ctrlName.toLowerCase() + item.toLowerCase()
				: item.toLowerCase();
			if (map.has(tag)) {
				map.get(tag)?.push(UIEngine);
			} else {
				map.set(tag, [UIEngine]);
			}
		});
	}

	/**
	 * 执行
	 *
	 * @private
	 * @param {any[]} UIEngineArray
	 * @param {IUIEngineInputParam<A>} args
	 * @memberof UIEngineContainer
	 */
	private async executeArrayEvent(
		UIEngineArray:
			| PanelEventUIEngine<A>[]
			| CtrlEventUIEngine<A>[]
			| ViewEventUIEngine<A>[],
		args: IUIEngineInputParam<A>
	): Promise<IUIEngineResult> {
		if (UIEngineArray.length == 1) {
			return UIEngineArray[0].asyncExcute(args);
		}
		const result: any = {
			ok: true,
			data: [],
		};
		await Promise.all(
			UIEngineArray.map(
				async (
					UIEngine:
						| PanelEventUIEngine<A>
						| CtrlEventUIEngine<A>
						| ViewEventUIEngine<A>
				) => {
					const res = await UIEngine.asyncExcute(args);
					result.ok = res.ok && res.ok;
					result.data.push(res.data);
					return res;
				}
			)
		);
		return result;
	}

	/**
	 * 执行视图事件逻辑
	 *
	 * @param {string} action
	 * @param {IUIEngineInputParam<A>} args
	 * @return {*}  {Promise<IUIEngineResult>}
	 * @memberof UIEngineContainer
	 */
	public async executeViewEvent(
		action: string,
		args: IUIEngineInputParam<A>
	): Promise<IUIEngineResult> {
		const tempUIEngine: ViewEventUIEngine<A>[] | undefined =
			this.viewEventUIEngineMap.get(action.toLowerCase());
		if (!tempUIEngine) {
			return { ok: true, data: [] };
		}
		return await this.executeArrayEvent(tempUIEngine, args);
	}

	/**
	 * 执行部件事件逻辑
	 *
	 * @param {string} action
	 * @param {IUIEngineInputParam<A>} args
	 * @return {*}  {Promise<IUIEngineResult>}
	 * @memberof UIEngineContainer
	 */
	public async executeCtrlEvent(
		action: string,
		args: IUIEngineInputParam<A>
	): Promise<IUIEngineResult> {
		const tempUIEngine = this.ctrlEventUIEngineMap.get(action.toLowerCase());
		if (!tempUIEngine) {
			return { ok: true, data: [] };
		}
		return await this.executeArrayEvent(tempUIEngine, args);
	}

	/**
	 * 执行面板事件逻辑
	 *
	 * @param {string} action
	 * @param {IUIEngineInputParam<A>} args
	 * @return {*}  {Promise<IUIEngineResult>}
	 * @memberof UIEngineContainer
	 */
	public async executePanelEvent(
		action: string,
		args: IUIEngineInputParam<A>
	): Promise<IUIEngineResult> {
		const tempUIEngine = this.panelEventUIEngineMap.get(action.toLowerCase());
		if (!tempUIEngine) {
			return { ok: true, data: [] };
		}
		return await this.executeArrayEvent(tempUIEngine, args);
	}

	/**
	 * 执行计数器逻辑
	 *
	 * @param {IUIEngineInputParam<A>} args
	 * @return {*}  {Promise<void>}
	 * @memberof UIEngineContainer
	 */
	public async executeTimer(args: IUIEngineInputParam<A>): Promise<void> {
		if (this.timerUIEngineMap.size > 0) {
			for (let tempUIEngine of this.timerUIEngineMap.values()) {
				if (tempUIEngine) {
					await tempUIEngine.asyncExcute(args);
				}
			}
		}
	}

	/**
	 *  设置项显示逻辑
	 *
	 * @memberof UIEngineContainer
	 */
	public executeItemLogic(args: IUIEngineInputParam<A>) {
		if (this.itemUIEngineMap.size > 0) {
			for (let tempUIEngine of this.itemUIEngineMap.values()) {
				if (tempUIEngine) {
					tempUIEngine.executeItemLogic(args);
				}
			}
		}
	}

	/**
	 * 执行自定义事件
	 *
	 * @param {*} opts
	 * @memberof UIEngineContainer
	 */
	public executeCustomEvent(action: any, opts: any) {
		if (this.customUIEngineMap.has(action)) {
			const tempUIEngine = this.customUIEngineMap.get(action);
			if (tempUIEngine) {
				return tempUIEngine.syncExcute(opts);
			}
		}
	}

	/**
	 * 销毁
	 *
	 * @return {*}  {Promise<void>}
	 * @memberof UIEngineContainer
	 */
	public async destroy(): Promise<void> {
		if (this.timerUIEngineMap.size > 0) {
			for (let tempUIEngine of this.timerUIEngineMap.values()) {
				if (tempUIEngine) {
					tempUIEngine.destroy();
				}
			}
		}
	}
}
